package com.alliky.core.utils

import android.content.Context
import android.content.SharedPreferences
import android.util.Base64
import com.alibaba.fastjson.JSON
import com.alliky.core.config.AppConfig
import java.io.*
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.util.*

/**
 * SharePreference相关的辅助类
 *
 * @author wxianing
 */
class SPUtils {
    /**
     * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
     *
     */
    private object SharedPreferencesCompat {
        private val sApplyMethod = findApplyMethod()

        /**
         * 反射查找apply的方法
         *
         * @return
         */
        private fun findApplyMethod(): Method? {
            try {
                val clz: Class<*> = SharedPreferences.Editor::class.java
                return clz.getMethod("apply")
            } catch (e: NoSuchMethodException) {
            }
            return null
        }

        /**
         * 如果找到则使用apply执行，否则使用commit
         *
         * @param editor
         */
        fun apply(editor: SharedPreferences.Editor) {
            try {
                if (sApplyMethod != null) {
                    sApplyMethod.invoke(editor)
                    return
                }
            } catch (e: IllegalArgumentException) {
            } catch (e: IllegalAccessException) {
            } catch (e: InvocationTargetException) {
            }
            editor.commit()
        }
    }

    companion object {
        /**
         * 保存在手机里面的文件名
         */
        const val FILE_NAME = "share_config"

        /**
         * 保存数据的方法，我们需要拿到保存数据的具体类型，然后根据类型调用不同的保存方法
         *
         * @param key
         * @param object
         */
        fun save(key: String?, `object`: Any?) {
            if (null == `object`) {
//            ToastUtil.shows(context,"Save object NullPointErexception!");
                return
            }
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            val editor = sp.edit()
            if (`object` is String) {
                editor.putString(key, `object` as String?)
            } else if (`object` is Int) {
                editor.putInt(key, (`object` as Int?)!!)
            } else if (`object` is Boolean) {
                editor.putBoolean(key, (`object` as Boolean?)!!)
            } else if (`object` is Float) {
                editor.putFloat(key, (`object` as Float?)!!)
            } else if (`object` is Long) {
                editor.putLong(key, (`object` as Long?)!!)
            } else {
                editor.putString(key, `object`.toString())
            }
            SharedPreferencesCompat.apply(editor)
        }

        /**
         * 得到保存数据的方法，我们根据默认值得到保存的数据的具体类型，然后调用相对于的方法获取值
         *
         * @param key
         * @param defaultObject
         * @return
         */
        operator fun get(key: String?, defaultObject: Any?): Any? {
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            if (defaultObject is String) {
                return sp.getString(key, defaultObject as String?)
            } else if (defaultObject is Int) {
                return sp.getInt(key, (defaultObject as Int?)!!)
            } else if (defaultObject is Boolean) {
                return sp.getBoolean(key, (defaultObject as Boolean?)!!)
            } else if (defaultObject is Float) {
                return sp.getFloat(key, (defaultObject as Float?)!!)
            } else if (defaultObject is Long) {
                return sp.getLong(key, (defaultObject as Long?)!!)
            }
            return null
        }

        /**
         * 针对复杂类型存储<对象>
         *
         * @param key
         * @param object
        </对象> */
        fun saveObject(key: String?, `object`: Any?) {
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            //创建字节输出流
            val baos = ByteArrayOutputStream()
            //创建字节对象输出流
            var out: ObjectOutputStream? = null
            try {
                //然后通过将字对象进行64转码，写入key值为key的sp中
                out = ObjectOutputStream(baos)
                out.writeObject(`object`)
                val objectVal = String(Base64.encode(baos.toByteArray(), Base64.DEFAULT))
                val editor = sp.edit()
                editor.putString(key, objectVal)
                editor.commit()
            } catch (e: IOException) {
                e.printStackTrace()
            } finally {
                try {
                    if (baos != null) {
                        baos.close()
                    }
                    out?.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }

        fun <T> getObject(key: String?, clazz: Class<T>?): T? {
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            if (sp.contains(key)) {
                val objectVal = sp.getString(key, null)
                val buffer = Base64.decode(objectVal, Base64.DEFAULT)
                //一样通过读取字节流，创建字节流输入流，写入对象并作强制转换
                val bais = ByteArrayInputStream(buffer)
                var ois: ObjectInputStream? = null
                try {
                    ois = ObjectInputStream(bais)
                    return ois.readObject() as T
                } catch (e: Exception) {
                    e.printStackTrace()
                } finally {
                    try {
                        if (bais != null) {
                            bais.close()
                        }
                        ois?.close()
                    } catch (e: IOException) {
                        e.printStackTrace()
                    }
                }
            }
            return null
        }

        /**
         * 保存List
         *
         * @param tag
         * @param datalist
         */
        fun <T> saveList(tag: String?, datalist: List<T>?) {
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            val editor = sp.edit()
            if (null == datalist || datalist.size <= 0) return
            //转换成json数据，再保存
            val strJson = JSON.toJSONString(datalist)
            editor.putString(tag, strJson)
            editor.commit()
        }

        /**
         * 获取List
         *
         * @param tag
         * @return
         */
        fun <T> getList(tag: String?, clazz: Class<T>?): List<T>? {
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            var dataList: List<T>? = ArrayList()
            val strJson = sp.getString(tag, null) ?: return dataList
            dataList = JSON.parseArray(strJson, clazz)
            return dataList
        }

        /**
         * 移除某个key值已经对应的值
         *
         * @param key
         */
        fun remove(key: String?) {
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            val editor = sp.edit()
            editor.remove(key)
            SharedPreferencesCompat.apply(editor)
        }

        /**
         * 清除所有数据
         */
        fun clear() {
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            val editor = sp.edit()
            editor.clear()
            SharedPreferencesCompat.apply(editor)
        }

        /**
         * 查询某个key是否已经存在
         *
         * @param key
         * @return
         */
        operator fun contains(key: String?): Boolean {
            val sp = AppConfig.getApplicationContext()
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            return sp.contains(key)
        }

        /**
         * 返回所有的键值对
         *
         * @return
         */
        val all: Map<String, *>
            get() {
                val sp = AppConfig.getApplicationContext()
                    .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
                return sp.all
            }
    }

    init {
        throw UnsupportedOperationException("cannot be instantiated")
    }
}